﻿using log4net;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using WpfApp1.Acme.ApplicationAttribute;
using WpfApp1.Acme.Template;

namespace WpfApp1.Acme.TemplateImpl {
    /// <summary>
    /// bean定义扫描器
    /// </summary>
    internal class ApplicationBeanDefinitionScanner : BeanDefinitionScanner {
        /** 日志对象 */
        private static readonly ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        /// <summary>
        /// 加载程序集
        /// </summary>
        /// <returns></returns>
        public Assembly loadPackage() {
            Assembly assembly = null;
            DirectoryInfo dir = new DirectoryInfo(Environment.CurrentDirectory);
            FileInfo[] files = dir.GetFiles();

            string name = ApplicationContext.getExecutingAssembly().GetName().Name;
            string pattern =  name + ".exe$|"+name+".dll$";
            /**(from infoResult in files where Regex.IsMatch(infoResult.Name, pattern) select infoResult).ToList().ForEach((result)=> {
             *  logger.Info("已加载: " + result.FullName + " 程序集");
             *   assembly = Assembly.LoadFrom(result.FullName);
             * });
             * 相对于：
             * foreach (FileInfo file in files) {
             *  if (Regex.IsMatch(file.FullName, pattern)) {
             *      logger.Info("已加载: " + file.FullName + " 程序集");
             *      return Assembly.LoadFile(file.FullName);
             *  }
             * }
             * */
            (from infoSetResult in files 
             where Regex.IsMatch(infoSetResult.Name, pattern)
             select infoSetResult).ToList().ForEach((result)=> {
                logger.Info("已加载: " + result.FullName + " 程序集");
                assembly = Assembly.LoadFrom(result.FullName);
            });
            return assembly;
        }

        /// <summary>
        /// 获取扫描器对象
        /// </summary>
        /// <returns></returns>
        public static ApplicationBeanDefinitionScanner get() {
          return new ApplicationBeanDefinitionScanner();
        }

        /// <summary>
        /// 扫描程序集中的指定包
        /// </summary>
        /// <param name="packagePath"></param>
        /// <param name="assembly"></param>
        public void scanning(in string packagePath, Assembly assembly) {
            DirectoryInfo dir = new DirectoryInfo(packagePath);
            try {
                FileInfo[] files = dir.GetFiles();
                DirectoryInfo[] dirs = dir.GetDirectories();
                /**相对于：
                 * foreach(FileInfo file in files) {
                 *   if (file.FullName.Contains(".cs")) { ... }
                 * }
                 * */
               (from fileInfoResultSet in files 
                where fileInfoResultSet.FullName.Contains(".cs") 
                select fileInfoResultSet).ToList().ForEach((result)=> {
                    string fullName = result.FullName;
                    fullName = fullName.Replace("\\", ".");
                    fullName = Regex.Match(fullName, Assembly.GetEntryAssembly().GetName().Name + ".*(?=.cs)").ToString();

                    if (fullName.Contains(".xaml")) {
                        fullName = Regex.Match(fullName, Assembly.GetEntryAssembly().GetName().Name + ".*(?=.xaml)").ToString();
                        logger.Info("扫描到视图: " + fullName);
                    } else { logger.Info("正在扫描: " + fullName); }

                    // 是否有Component特性
                    Attribute attribute = assembly.GetType(fullName)?.GetCustomAttribute(typeof(Component));
                    ExecutionAttribute.getAttributeThreeStrategy()[attribute?.GetType() ?? typeof(string)](assembly, attribute, fullName);

                    // 是否有ViewData特性
                    attribute = assembly.GetType(fullName)?.GetCustomAttribute(typeof(ViewData));
                    ExecutionAttribute.getAttributeThreeStrategy()[attribute?.GetType() ?? typeof(string)](assembly, attribute, fullName);
                });

                /**foreach (DirectoryInfo dirInfo in dirs) {
                 *    scanning(dirInfo.FullName, assembly);
                 * }
                 * */
                dirs.ToList().ForEach((dirInfo) => {
                    scanning(dirInfo.FullName, assembly);
                });

            } catch (Exception e) {
                logger.Error(e.Message);
            }

        }

    }
}
